/* program bar program by @author chenxin <chenxin619315@gmail.com> */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <unistd.h>

typedef struct {
	char chr;	/* tip char */
	char *title;/* tip string */
	char style; /* progress style */
	char *pro;
	int max;	/* maximum value */
	float offset;
}progress_t;

#define PROGRESS_STYLE_NUM	0
#define PROGRESS_STYLE_CHR  1
#define PROGRESS_STYLE_BGC	2

void progress_init(progress_t *bar, char *title, int max, char style);
void progress_show(progress_t *bar, float bit);
void progress_destroy(progress_t *bar);

#define SHOW_NUM 80 /* this num determine how long '[#...#]' show */

int main(int argc, char **argv)
{
	int i;
	progress_t bar_num;
	progress_t bar_chr;
	progress_t bar_bgc;

	progress_init(&bar_num, "bar_num --> ", SHOW_NUM, PROGRESS_STYLE_NUM);
	progress_init(&bar_chr, "", SHOW_NUM, PROGRESS_STYLE_CHR);
	progress_init(&bar_bgc, "", SHOW_NUM, PROGRESS_STYLE_BGC);

	for (i = 0; i <= bar_num.max; i++) {
		progress_show(&bar_num, i/(float)bar_num.max);
		usleep(100000);
	}
	printf("\n");

	for (i = 0; i <= bar_num.max; i++) {
		progress_show(&bar_chr, i/(float)bar_num.max);
		usleep(100000);
	}
	printf("\n");

	for (i = 0; i <= bar_num.max; i++) {
		progress_show(&bar_bgc, i/(float)bar_num.max);
		usleep(100000);
	}
	printf("\n");

	progress_destroy(&bar_num);
	progress_destroy(&bar_chr);
	progress_destroy(&bar_bgc);
	return 0;
}

void progress_init(progress_t *bar, char *title, int max, char style)
{
	bar->chr = '#';
	bar->title = title;
	bar->style = style;
	bar->max = max;
	bar->offset = 100 / (float)max; 
	bar->pro = (char *) malloc(max+1);
	if (style == PROGRESS_STYLE_BGC)
		memset(bar->pro, '\0', max+1);
	else {
		memset(bar->pro, 32, max); /* space */
		memset(bar->pro+max, '\0', 1);
	}
}

void progress_show(progress_t *bar, float bit)
{
	int val = (int)(bit * bar->max);
	switch ( bar->style ) 
	{
		case PROGRESS_STYLE_NUM:
			printf("\033[?25l\033[31m\033[1m%s%d%%\033[?25h\033[0m\r",
					bar->title, (int)(bar->offset * val));
			fflush(stdout);
			break;
		case PROGRESS_STYLE_CHR:
			memset(bar->pro, '#', val);
			printf("\033[?25l\033[31m\033[1m%s[%-s] %d%%\033[?25h\033[0m\r", 
					bar->title, bar->pro, (int)(bar->offset * val));
			fflush(stdout);
			break;
		case PROGRESS_STYLE_BGC:
			memset(bar->pro, 32, val);
			printf("\033[?25l\033[31m\033[1m%s\033[41m %d%% %s\033[?25h\033[0m\r", 
					bar->title, (int)(bar->offset * val), bar->pro);
			fflush(stdout);
			break;
	}
}

void progress_destroy(progress_t *bar)
{
    free(bar->pro);
}
